package cn.com.fig.portal;

import cn.com.fig.portal.constants.Constants;
import cn.com.fig.portal.domain.User;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 拦截菜单访问，验证用户是否已登陆及是否有权限访问
 * 抽象类，子系统需实现该类完成相关业务。
 * @author eternalfig
 *
 */
public abstract class AccessFilter implements Filter{

    Logger logger = LoggerFactory.getLogger(getClass());

    protected String ssoUri;

    protected FilterConfig filterConfig;
//     不验证session的url,包含下列字符的URL不验证session
    protected static String[] NOVALIDATE_SESSION;
//    验证token是否有效的服务地址
    protected static String TOKEN_VALIDATE_PATH;
//    SSO登陆页
    protected static String LOGIN_PATH;
    @Override
    public void init(FilterConfig fc) throws ServletException{
        this.filterConfig = fc;
        String temp = fc.getInitParameter("NOVALIDATE_SESSION");
        if(temp != null)
            NOVALIDATE_SESSION = temp.split(",");
        TOKEN_VALIDATE_PATH = ssoUri + fc.getInitParameter("TOKEN_VALIDATE_PATH");
        LOGIN_PATH = ssoUri + fc.getInitParameter("LOGIN_PATH");
    }
	@Override
	public void doFilter(ServletRequest resquest, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) resquest;
		HttpServletResponse res = (HttpServletResponse) response;
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "POST, GET");
        res.setHeader("Access-Control-Max-Age", "3600");
        res.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, Access-Toke");


//		判断访问地址是否不需要验证是否登陆
        if(validateSesion(req)){
            chain.doFilter(req, res);
            return;
        }

//		首先从http header中获取token，通常桌面软件会把token放到header中发送服务器端
		String token = req.getHeader(Constants.TOKEN_COOKIE_NAME);
		String sessionid = req.getHeader(Constants.SESSION_ID);
        String userId = (String)req.getParameter("userId");
        if(userId == null)
            userId = (String) req.getSession().getAttribute("userId");

		if(token == null) {
//		    其次可以从cookie中获取token信息，一般通过浏览器访问时，token会放在cookie中
			token = CookieUtil.getTokenFromCookie(req, Constants.TOKEN_COOKIE_NAME);
			sessionid = CookieUtil.getTokenFromCookie(req, Constants.SESSION_ID);
		}
		if(token == null || userId == null || sessionid == null) {
			redirectLoginPage(req,res);
			return;
		}

        User user = (User)req.getSession().getAttribute("user");
//			用户session未生成，验证token是否有效
		if(user == null) {
		    Map map = this.tokenCheck(userId,token,sessionid);
//			token有效，从缓存中提取用户session信息
            if(map != null) {
			    user = (User)map.get("user");
                req.getSession().setAttribute("user", user);
                req.getSession().setAttribute("userId", user.getUserId());
//			     加载其他额外信息至session中。需子系统自行实现
                initSession(req, res);
            }else{
//                res.setHeader("sessionstatus", "timeout");
//                res.sendError(518, "session timeout.");
                redirectLoginPage(req,res);
                return;
            }
		}
        if(!validateAccessUrlPremission(req,res)){
            return;
        }

        chain.doFilter(req, res);
	}

	private void redirectLoginPage(HttpServletRequest req,HttpServletResponse res) throws IOException {
        req.getSession().invalidate();
        res.setContentType("text/html;charset=utf-8");
        PrintWriter out = res.getWriter();
        out.println("<script language='javascript' type='text/javascript'>");
        out.println("window.top.location.href='" + LOGIN_PATH +"'");
        out.println("</script>");
    }

    /**
     * 判断访问地址是否不需要验证登陆状态
     * @param req
     * @return
     */
    private boolean validateSesion(HttpServletRequest req){
        String context = req.getRequestURI();
        for (String s : NOVALIDATE_SESSION) {
            if (context.indexOf(s) > -1) {
                return true;
            }
        }
        return false;
    }
    public abstract boolean validateAccessUrlPremission(HttpServletRequest req, HttpServletResponse res);

	public Map tokenCheck(String userId,String token,String sessionId){
        HttpURLConnection httpConn = null;
        BufferedReader in = null;
        StringBuffer outStr = new StringBuffer();
        StringBuilder sb = new StringBuilder(TOKEN_VALIDATE_PATH)
                .append("?userId=").append(userId)
                .append("&token=").append(token)
                .append("&sessionId=").append(sessionId);
        try {
            URL url = new URL(sb.toString());
            in = new BufferedReader(new InputStreamReader(url.openStream(),"UTF-8") );
            String str = null;
            //一行一行进行读入
            while((str = in.readLine()) != null) {
                outStr.append(str);
            }
        } catch (Exception e) {
            logger.error("",e);
            return null;
        }finally{
            try{
                if(in!=null) {
                    in.close(); //关闭流
                }
            }catch(IOException ex) {
                logger.error("",ex);
            }
        }

//        如果返回空字符串，说明用户没有在权限中心登陆，需要跳转到登陆页面
        if(outStr.length() == 0)
            return null;

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

        Map result = null;
        try {
            result = objectMapper.readValue(outStr.toString(), Map.class);
            Map userMap = (Map)result.get("user");
            User user = objectMapper.readValue(objectMapper.writeValueAsString(userMap), User.class);
            result.put("user",user);
        } catch (Exception e) {
            logger.error("",e);
            return null;
        }
        return result;
    }
    /**
     * 子类实现额外加载需放到session中信息
     * @param req
     * @param res
     */
	public abstract void initSession(HttpServletRequest req, HttpServletResponse res);

}
